package bszt.ele;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.StringTokenizer;

public class Code03 {

    /**
     * 问题描述
     * K小姐是一位魔法森林的管理员。森林中有n个魔法节点和m条魔法通道连接这些节点。每条魔法通道都有一个魔力值
     * K小姐想要改造这个森林，使得所有节点都能相互连通，同时保证最弱的魔法通道尽可能强大
     * K小姐有k次机会，每次可以选择一条魔法通道，将其魔力值提升1点。在完成所有改造后，K小姐需要选择n-1条魔法通道，使得所有节点都能相互连通。这些选中的通道将形成一棵魔法树
     * K小姐的目标是使这棵魔法树中最弱的魔法通道尽可能强大。请你帮助K小姐计算，在最优的改造方案下，魔法树中最弱通道的魔力值最大可以达到多少
     * <p></p>
     * 输入格式
     * 第一行包含三个整数n，m，k，分别表示魔法节点的数量、魔法通道的数量和K小姐可以进行的改造次数
     * 接下来的m行，每行包含三个整数a_i,b_i,c_i，表示第i条魔法通道连接节点a_i和b_i，其初始魔力值为c_i
     * 保证所有魔法节点都是连通的，且不存在重复的魔法通道
     * <p></p>
     * 输出格式
     * 输出一个整数，表示在最优改造方案下，魔法树中最弱通道的最大可能魔力值
     */

    // 边类，用于存储边的信息
    static class Edge implements Comparable<Edge> {
        int a, b;
        long c;

        Edge(int a, int b, long c) {
            this.a = a;
            this.b = b;
            this.c = c;
        }

        @Override
        public int compareTo(Edge o) {
            return Long.compare(o.c, this.c);
        }
    }

    // 并查集类，用于检测图的连通性
    static class UnionFind {
        int[] parent;

        UnionFind(int n) {
            parent = new int[n];
            for (int i = 0; i < n; i++) parent[i] = i;
        }

        int find(int x) {
            if (parent[x] != x) parent[x] = find(parent[x]);
            return parent[x];
        }

        void union(int x, int y) {
            int px = find(x), py = find(y);
            if (px != py) {
                parent[px] = py;
            }
        }

        boolean isSame(int x, int y) {
            x = find(x);
            y = find(y);
            return x == y;
        }
    }

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        int n = Integer.parseInt(st.nextToken());
        int m = Integer.parseInt(st.nextToken());
        long k = Long.parseLong(st.nextToken());

        // 读取边的信息
        Edge[] edges = new Edge[m];
        for (int i = 0; i < m; i++) {
            st = new StringTokenizer(br.readLine());
            int a = Integer.parseInt(st.nextToken());
            int b = Integer.parseInt(st.nextToken());
            long c = Long.parseLong(st.nextToken());
            edges[i] = new Edge(a - 1, b - 1, c);
        }

        // 按魔力值降序排序
        Arrays.sort(edges);
        UnionFind uf = new UnionFind(n);
        List<Long> treeEdges = new ArrayList<>();

        // Kruskal算法求最大生成树
        for (Edge e : edges) {
            if (!uf.isSame(e.a, e.b)) {
                uf.union(e.a, e.b);
                treeEdges.add(e.c);
            }
        }

        // 二分查找最小魔力值
        long left = treeEdges.get(treeEdges.size() - 1);
        long right = (long) 1e14 + k;
        while (left < right) {
            long mid = left + (right - left + 1) / 2;
            long needed = 0;
            for (long c : treeEdges) {
                needed += Math.max(0, mid - c);
            }
            if (needed <= k) {
                left = mid;
            } else {
                right = mid - 1;
            }
        }

        // 输出结果
        System.out.println(left);
    }
}

